package cn.wj.school.app.net.client.handler;

import cn.wj.school.app.net.client.ecode.MsgDecoder;
import cn.wj.school.app.net.client.ecode.MsgEncoder;
import cn.wj.school.common.handler.ChannelHandlerHolder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @Author: yueding
 * @Description:客户端重连检测，当发现当前的链路不稳定关闭之后，进行12次重连
 * @Date: Created in 20:19 2018/12/27
 * @Modified By: yueding Copyright(c) cai-inc.com
 */
@Slf4j
@ChannelHandler.Sharable
public class ClientReConnection extends ChannelInboundHandlerAdapter implements TimerTask, ChannelHandlerHolder {

    private final Bootstrap bootstrap;
    private final Timer timer;
    private final int port;

    private final String host;

    private final ConnectorIdleStateHandler connectorIdleStateHandler = new ConnectorIdleStateHandler();

    private volatile boolean reconnect;


    public ClientReConnection(Bootstrap bootstrap, Timer timer, int port, String host, boolean reconnect) {
        this.bootstrap = bootstrap;
        this.timer = timer;
        this.port = port;
        this.host = host;
        this.reconnect = reconnect;
    }

    /**
     * channel链路每次active的时候，将其连接的次数重新☞ 0
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println("当前链路已经激活了，重连尝试次数重新置为0");
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("链接关闭");
        if (reconnect) {
            // 每隔5秒进行重连
            timer.newTimeout(this, 5000, TimeUnit.MILLISECONDS);
        }
        ctx.fireChannelInactive();
    }


    @Override
    public void run(Timeout timeout) throws Exception {

        ChannelFuture future;
        // bootstrap已经初始化好了，只需要将handler填入就可以了
        synchronized (bootstrap) {
            bootstrap.handler(new ChannelInitializer() {

                @Override
                protected void initChannel(Channel ch) throws Exception {

                    ch.pipeline().addLast(handlers());
                }
            });
            future = bootstrap.connect(host, port);
        }
        // future对象
        future.addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                boolean succeed = f.isSuccess();

                // 如果重连失败，则调用ChannelInactive方法，再次出发重连事件，一直尝试
                if (!succeed) {
                    log.warn("重连失败");
                    f.channel().pipeline().fireChannelInactive();
                } else {
                    log.info("重连成功");
                }
            }
        });

    }


    @Override
    public ChannelHandler[] handlers() {
        return new ChannelHandler[] {this, new MsgDecoder(1024 * 4, 0, 4, 0, 4), new LengthFieldPrepender(4),
                new MsgEncoder(), new IdleStateHandler(0, 10, 0, TimeUnit.SECONDS), connectorIdleStateHandler,
                new ClientChannelHandler()};
    }
}

